package com.crm.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import com.crm.dao.BaseDao;

/**
 * @author Yusei
 * 通用dao的实现类
 */
public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T>{
	// 注意这个c是大写的，大写的，大写的
	private Class clazz;
	// 提供构造方法，传入具体类型的class，也就是那个<T>
	// 以构造方法实现传入<T>
	/*public BaseDaoImpl(Class clazz){
		this.clazz = clazz;
	}*/

	/**	
	 * 不想子类上有构造方法，必须在父类中提供无参构造方法，并且在无参构造方法中获得具体类型的Class
	 * 具体类型的Class是参数类型中实际类型的参数
	 * 好像，为了少2行代码，多加了很多行代码了。。。
	 */
	public BaseDaoImpl(){
		// 反射：首先得获得Class
		// 会获得正在调用的那个类的Class，CustomerDaoImpl或者LinkManDaoImpl
		Class clazz = this.getClass();
		// 获得参数化类型：BaseDaoImpl<Customer>;BaseDaoImpl<LinkMan>
		// 要导入的包是java.lang.reflect.Type;
		Type type = clazz.getGenericSuperclass();
		// System.out.println(type);
		// 得到了Type之后，要将type强制转换成参数化的类型
		ParameterizedType pType = (ParameterizedType) type;
		// 通过参数化类型获得实际类型参数，为什么是Type数组？
		// e.g. Map<String, Integer>，所以明白为什么需要是type数组了吧
		Type[] types = pType.getActualTypeArguments();
		// 这里只需要获取第一个元素即可
		this.clazz = (Class)types[0];
	}
	
	@Override
	// 增
	public void save(T t) {
		this.getHibernateTemplate().save(t);
	}

	@Override
	// 删
	public void delete(T t) {
		this.getHibernateTemplate().delete(t);
	}

	@Override
	// 改
	public void update(T t) {
		this.getHibernateTemplate().update(t);
	}

	/**
	 * 通用查询方法
	 * 首先，需要获得当前调用的类（Customer还是LinkMan？）
	 * 解决方法1：
	 * 在实现类的构造方法中传入一个Class
	 */
	
	@Override
	// 根据id查询
	public T findById(Serializable id) {
		return (T) this.getHibernateTemplate().get(clazz, id);
	}
	
	// 查询所有
	public List<T> findAll(){
		return (List<T>)this.getHibernateTemplate().find("FROM " + clazz.getSimpleName());
	}

	@Override
	// 统计个数
	public Integer findCount(DetachedCriteria detachedCriteria) {
		// 设置统计个数的条件
		detachedCriteria.setProjection(Projections.rowCount());
		List<Long> list = (List<Long>)this.getHibernateTemplate().findByCriteria(detachedCriteria);
		if (list.size() > 0) {
			return list.get(0).intValue();
		}
		return null;
	}

	@Override
	// 分页查询
	public List<T> findByPage(DetachedCriteria detachedCriteria, Integer begin, Integer pageSize) {
		detachedCriteria.setProjection(null);
		return (List<T>)this.getHibernateTemplate().findByCriteria(detachedCriteria, begin, pageSize);
	}


}
